/**
 * Time：2024.04.28
 * Content：线程池
 * Author：Qian You
 */
#include <iostream>
#include <bits/stdc++.h>
// 头文件
#include <thread>
using namespace std;

class ThreadPool
{
public:
    // 提前开辟线程个数，每个线程循环去任务队列去任务
    ThreadPool(int num) : stop(false)
    {
        for (int i = 0; i < num; i++)
        {
            threads.emplace_back([this]
                                 {
                while(1){
                    unique_lock<mutex> lock(mtx);
                    // 等待直至 队列有任务 或者 线程终止
                    condition.wait(lock, [this]{
                        return !tasks.empty() || stop;
                    });
                    // 线程终止
                    if(stop && tasks.empty()){
                        return ;
                    }
                    
                    function<void()> task(move(tasks.front()));
                    tasks.pop();
                    task();
                    lock.unlock();
                } });
        }
    }
    ~ThreadPool()
    {
        unique_lock<mutex> lock(mtx);
        stop = true;

        // 通知所有线程工作 执行
        condition.notify_all();
        for (auto &t : threads)
        {
            t.join();
        }
    }
    
    // 去任务队列加任务
    // 函数模板里面&&右值引用是万能引用
    template <class F, class... Args>
    void enqueue(F &&f, Args &&...args)
    {
        // 通用引用，完美转发，因为参数列表可能是左值引用也有可能是右值引用
        function<void()> task = bind(forward<F>(f), forward<Args>(args)...);
        {
            unique_lock<mutex> lock(mtx);
            // move实现移动语义，左值转成右值
            tasks.emplace(move(task));
        }
        condition.notify_one();
    }

private:
    vector<thread> threads;        // 线程数组
    queue<function<void()>> tasks; // 任务队列
    mutex mtx;
    condition_variable condition;
    bool stop;
};

int main()
{
    ThreadPool pool(4);
    for (int i = 0; i < 10; i++)
    {
        pool.enqueue([i]
                     {
            cout<<"task: "<<i<<"is running "<<__TIME__<<endl;
            this_thread::sleep_for(chrono::microseconds(100));
            cout<<"task: "<<i<<"is done "<<__TIME__<<endl; });
    }
    return 0;
}